package gupao.concurrency.threadpool.futures;

import gupao.concurrency.utils.ThreadPoolService;
import gupao.concurrency.utils.Utils;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
public class SimpleFutureSample {

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = ThreadPoolService.getOrCreateThreadPoolExecutor("simple-future",
                4,16);

        Future<String> normalFuture = executor.submit(() -> {
            log.info("Normal task running..");
            Utils.sleepIgnoreExp(200);
            return "NormalTaskResult";
        });

        Future<String> bizExpFuture = executor.submit(() -> {
            log.info("Exp task running..");
            Utils.sleepIgnoreExp(800);
            throw new RuntimeException("exception task.");
        });
        AtomicBoolean stop = new AtomicBoolean(false);
        Future<String> interruptFuture = executor.submit(() -> {
            while(!stop.get()){
                log.info("interrupt task running..");
                TimeUnit.MILLISECONDS.sleep(100);
            }
            return "interrupt task result";
        });

        executor.execute(() -> {
            Utils.sleepIgnoreExp(2000);
            log.info("NormalTaskResult: {}", getFutureResult(normalFuture));
            log.info("BizExpTaskResult: {}", getFutureResult(bizExpFuture));
            log.info("InterruptTaskResult: {}", getFutureResult(interruptFuture));
        });

        while(!normalFuture.isDone() || !bizExpFuture.isDone()){
            log.info("normalFuture or bizExpFuture not done");
            Utils.sleepIgnoreExp(100);
        }
        log.info("cancel interrupt task: {}", interruptFuture.cancel(true));
        executor.shutdown();
        log.info("shutdown called");
        executor.awaitTermination(5, TimeUnit.SECONDS);
    }

    static String getFutureResult(Future<String> f){
        try {
            return f.get();
        } catch (Exception e) {
            log.error("{} occurred", e.getClass().getSimpleName());
            return null;
        }
    }
}
